package concurrent;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * TODO 简单说明
 *
 * @author yangyang
 * @date 2017/7/24 13:49
 * @email kekecany@163.com
 */
class Chopstick {

    private boolean taken = false;

    private final int id;

    Chopstick(int id) {
        this.id = id;
    }


    synchronized void take() throws InterruptedException {
        while (taken) {
            wait();
        }
        taken = true;
    }

    synchronized void drop() {
        taken = false;
        notifyAll();
    }

    @Override
    public String toString() {
        return "" + id;
    }
}

class Philosopher implements Runnable{

    private final int ponderFactor;
    private final int id;
    private Chopstick left;
    private Chopstick right;
    private Random random = new Random(47);

    Philosopher(int ponderFactor, int id, Chopstick left, Chopstick right) {
        this.ponderFactor = ponderFactor;
        this.id = id;
        this.left = left;
        this.right = right;
    }

    private void pause() throws InterruptedException {
        if (ponderFactor == 0) return;
        TimeUnit.MILLISECONDS.sleep(random.nextInt(250 * ponderFactor));
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                System.out.println(this + " is thinking...");
                pause();
                System.out.println(this + " takes " + left);
                left.take();
                System.out.println(this + " takes " + right);
                right.take();
                System.out.println(this + " is eating...");
                pause();
                System.out.println(this + " drops " + left);
                left.drop();
                System.out.println(this + " drops " + right);
                right.drop();
            }
        } catch (InterruptedException e) {
            System.out.println();
        }
    }

    @Override
    public String toString() {
        return "Philosopher{" +
                "id=" + id +
                '}';
    }
}

public class DeadlockingDiningPhilosophers {
    public static void main(String[] args) throws InterruptedException {
        int philosopherNum = 5;
        int ponder = 0;
        ExecutorService executorService = Executors.newCachedThreadPool();
        Chopstick[] chopsticks = new Chopstick[philosopherNum];
        for (int i = 0; i < philosopherNum; i++) {
            chopsticks[i] = new Chopstick(i);
        }
        for (int i = 0; i < philosopherNum; i++) {
            executorService.execute(new Philosopher(ponder, i, chopsticks[i], chopsticks[(i+1) % philosopherNum]));
        }
        TimeUnit.SECONDS.sleep(50);
        executorService.shutdownNow();
    }
}
